'''
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License") you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http:#www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
'''
from base.rdf.impl.InfModelImpl import InfModelImpl
from base.rdf.impl.ModelCom import ModelCom

#import java.util.Set;

#import org.apache.jena.assembler.Assembler;
#import org.apache.jena.assembler.AssemblerHelp;
#import org.apache.jena.graph.GraphMemFactory;
#import org.apache.jena.graph.Graph;
#import org.apache.jena.graph.compose.Union;
#import org.apache.jena.graph.impl.SimpleGraphMaker;
#import org.apache.jena.ontology.OntModel;
#import org.apache.jena.ontology.OntModelSpec;
#import org.apache.jena.ontology.ProfileRegistry;
#import org.apache.jena.ontology.impl.OntModelImpl;
#import org.apache.jena.rdf.model.impl.InfModelImpl;
#import org.apache.jena.rdf.model.impl.ModelCom;
#import org.apache.jena.rdf.model.impl.ModelMakerImpl;
#import org.apache.jena.reasoner.InfGraph;
#import org.apache.jena.reasoner.Reasoner;
#import org.apache.jena.reasoner.ReasonerRegistry;
#import org.apache.jena.sys.JenaSystem;

'''
 * ModelFactory provides methods for creating standard kinds of Model.
 * (ModelFactoryBase is helper functions for it).
'''

from abc import ABC, abstractmethod

class ModelFactory():
    # static:
    #     JenaSystem.init()
    

    '''
     * No-one can make instances of this.
    '''
    # param 
    # result private
    # def ModelFactory(self):
    

    '''
     * Answer a Model constructed from the single resource in
     * <code>singleRoot</code> of type <code>ja:Model</code>.
     * See the Assembler howto (doc/assembler/assembler-howto.html)
     * for documentation of Assembler descriptions. See also
     * <code>findAssemblerRoots</code> to find the set of possible
     * roots in a description, and <code>assemblerModelFrom(Resource)</code>
     * for assembling a model from its single description.
    '''
    # param Model singleRoot
    # result static Model
    @staticmethod
    def assembleModelFrom(singleRoot):
        return ModelFactory.assembleModelFrom(AssemblerHelp.singleModelRoot(singleRoot))
    

    '''
     * Answer a Set of resources present in <code>m</code> that are
     * explicitly or implicitly of type ja:Object, ie, suitable as roots for
     * <code>assemblerModelFrom</code>. Note that the resource
     * objects returned need <i>not</i> have <code>m</code> as
     * their <code>getModel()</code> - they may be members of an
     * extended constructed model.
    '''
    # param Model m
    # result static Set<Resource>
    # @staticmethod
    # def findAssemblerRoots(m):
    #     return AssemblerHelp.findAssemblerRoots(self)
    

    '''
     * Answer a Model as described the Assembler specification rooted
     * at the Resource <code>root</code> in its Model. <code>Resource</code>
     * must be of rdf:type <code>ja:Object</code>, where <code>ja</code>
     * is the prefix of Jena Assembler objects.
    '''
    # param Resource root
    # result static Model
    @staticmethod
    def assembleModelFromWithResource(root):
        return Assembler.general.openModel(root)
    

    '''
     * Answer a fresh Model with the default specification.
    '''
    # param 
    # result static Model
    @staticmethod
    def createDefaultModel():
        return ModelCom(GraphMemFactory.createGraphMem())
    

    '''
     * Answer a model that encapsulates the given graph. Existing prefixes are
     * undisturbed.
     *
     * @param g A graph structure
     * @return A model presenting an API view of graph g
    '''
    # param Graph g
    # result static Model
    @ staticmethod
    def createModelForGraph(g):
        return ModelCom(g)
    

    '''
     * Answer a ModelMaker that constructs memory-based Models that do
     * not persist past JVM termination.
     *
     * @return a ModelMaker that constructs memory-based models
    '''
    # param 
    # result static ModelMaker
    # @staticmethod
    # def createMemModelMaker(self):
    #     return ModelMakerImpl(new SimpleGraphMaker(self)
    

    '''
     * Return a Model through which all the RDFS entailments
     * derivable from the given model are accessible. Some work is done
     * when the inferenced model is created but each query will also trigger some
     * additional inference work.
     *
     * @param model the Model containing both instance data and schema assertions to be inferenced over
    '''
    # param Model model
    # result static InfModel
    @staticmethod
    def createRDFSModel(model):
        reasoner = ReasonerRegistry.getRDFSReasoner()
        graph = reasoner.bind(model.getGraph())
        return InfModelImpl(graph)
    

    '''
     * Return a Model through which all the RDFS entailments
     * derivable from the given data and schema models are accessible.
     * There is no strict requirement to separate schema and instance data between the two
     * arguments.
     *
     * @param model  a Model containing instance data assertions
     * @param schema a Model containing RDFS schema data
    '''
    # param Model schema, Model model
    # result static InfModel
    @staticmethod
    def createRDFSModel(schema, model):
        reasoner = ReasonerRegistry.getRDFSReasoner()
        graph = reasoner.bindSchema(schema.getGraph()).bind(model.getGraph())
        return InfModelImpl(graph)
    

    '''
     * Build an inferred model by attaching the given RDF model to the given reasoner.
     *
     * @param reasoner the reasoner to use to process the data
     * @param model    the Model containing both instance data and schema assertions to be inferenced over,
     *                 any statements added to the InfModel will be added to this underlying data model.
    '''
    # param Reasoner reasoner, Model model
    # result static InfModel
    @staticmethod
    def createInfModel(reasoner, model):
        graph = reasoner.bind(model.getGraph())
        return InfModelImpl(graph)
    

    '''
     * Build an inferred model by attaching the given RDF model to the given reasoner.
     * This form of the call allows two data sets to be merged and reasoned over -
     * conventionally one contains schema data and one instance data but this is not
     * a formal requirement.
     *
     * @param reasoner the reasoner to use to process the data
     * @param schema   a Model containing RDFS schema data
     * @param model    a Model containing instance data assertions, any statements added to the InfModel
     *                 will be added to this underlying data model.
    '''
    # param Reasoner reasoner, Model schema, Model model
    # result static InfModel
    @staticmethod
    def createInfModel(reasoner, schema, model):
        graph = reasoner.bindSchema(schema.getGraph()).bind(model.getGraph())
        return InfModelImpl(graph)
    

    '''
     * Build an inference model from an InfGraph. Graphs and InfGraphs
     * are internal implementation level objects rather than normal user
     * objects so this method should only be used if you are sure this is
     * what you need.
     *
     * @param g and inference graph
     * @return the same graph wrapped up as an InfModel
    '''
    # param InfGraph g
    # result static InfModel
    @staticmethod
    def createInfModel(g):
        return InfModelImpl(g)
    

    '''
     * <p>
     * Answer a Ontology model which will process in-memory models of
     * ontologies expressed the default ontology language (OWL).
     * The default document manager
     * will be used to load the ontology's included documents.
     * </p>
     * <p><strong>Note:</strong>The default model chosen for OWL and RDFS
     * includes a weak reasoner that includes some entailments (such as
     * transitive closure on the sub-class and sub-property hierarchies). Users
     * who want either no inference at all, or alternatively
     * more complete reasoning, should use
     * one of the other <code>createOntologyModel</code> methods that allow the
     * preferred OntModel specification to be stated.</p>
     *
     * @return A Ontology model
     * @see OntModelSpec#getDefaultSpec
     * @see #createOntologyModel(OntModelSpec, Model)
    '''
    # param 
    # result static OntModel
    @staticmethod
    def createOntologyModel():
        return createOntologyModel(ProfileRegistry.OWL_LANG)
    


    '''
     * <p>
     * Answer a Ontology model which will process in-memory models of
     * ontologies in the given language.
     * The default document manager
     * will be used to load the ontology's included documents.
     * </p>
     *
     * @param languageURI The URI specifying the ontology language we want to process
     * @return A Ontology model
     * @see OntModelSpec#getDefaultSpec
    '''
    # param String languageURI
    # result static OntModel
    @staticmethod
    def createOntologyModel(languageURI):
        return createOntologyModel(OntModelSpec.getDefaultSpec(languageURI), None)
    


    '''
     * <p>
     * Answer a Ontology model which will process in-memory models of
     * ontologies expressed the default ontology language (OWL).
     * The default document manager
     * will be used to load the ontology's included documents.
     * </p>
     *
     * @param spec  An ontology model specification that defines the language and reasoner to use
     * @param maker A model maker that is used to get the initial store for the ontology (unless
     *              the base model is given),
     *              and create addtional stores for the models in the imports closure
     * @param base  The base model, which contains the contents of the ontology to be processed
     * @return A Ontology model
     * @see OntModelSpec
    '''
    # param OntModelSpec spec, ModelMaker maker, Model base
    # result static OntModel
    @staticmethod
    def createOntologyModel(spec, maker, base):
        # OntModelSpec
        _spec = OntModelSpec(spec)
        _spec.setImportModelMaker(maker)
        return createOntologyModel(_spec, base)
    


    '''
     * <p>
     * Answer a Ontology model, constructed according to the given ontology model specification,
     * and starting with the ontology data in the given model.
     * </p>
     *
     * @param spec An ontology model specification object, that will be used to construct the ontology
     *             model with different options of ontology language, reasoner, document manager and storage model
     * @param base An existing model to treat as an ontology model, or null.
     * @return A Ontology model
     * @see OntModelSpec
    '''
    # param OntModelSpec spec, Model base
    # result static OntModel
    @staticmethod
    def createOntologyModelWithSpecAndBase(spec, base):
        return OntModelImpl(spec, base)
    

    '''
     * Answer a Ontology model constructed according to the specification, which includes
     * a ModelMaker which will create the necessary base model.
    '''
    # param OntModelSpec spec
    # result static OntModel
    @staticmethod
    def createOntologyModelWithSpec(spec):
        return OntModelImpl(spec)
    


    '''
     * Answer a Model that is the dynamic union of two other models. By
     * <i>dynamic union</i>, we mean that changes to either <code>m1</code>
     * or <code>m2</code> will be reflected in the result model, and
     * <i>vice versa</i>: specifically, additions to and removals from the union
     * will be implemented as operations on <code>m1</code>
     * <strong>only</strong>. See also the behaviour of OntModel
     * and the MultiUnion class.
     * <p>
     * <code>createUnion</code> only creates two-element unions.
    '''
    # param Model m1, Model m2
    # result static Model
    # @staticmethod
    # def createUnion(m1, m2):
    #     return ModelFactory.createModelForGraph(Union(m1.getGraph(), m2.getGraph()))
    


